<?php

class SmsController extends AppController {

    public $uses = array(
        'ModuleSmsAccount', 'ModuleSmsAccountBroadcast', 'ModuleSmsBroadcastList', 'ModuleSmsBroadcastlistContact', 
        'ModuleSmsAccountInstantMessage', 'OrganisationNotification'
    );
    public $components = array('Sms');

    public function broadcast($action) {
        $response = array();

        switch ($action) {
            case 'lists':
                $response = $this->broadcastLists();
                break;
            
            case 'predefined_lists':
                $response = $this->broadcastLists(true);
                break;
            
            case 'history':
                $response = $this->broadcastHistory();
                break;
            
            case 'schedule':
                $response = $this->scheduleBroadcastMessage();
                break;
        }

        return $this->_response($response);
    }
    
    public function broadcast_list($action = 'fetch') {
        $response = array();
        
        switch($action) {
            case 'fetch':
                $response = $this->getBroadcastList();
                break;
            
            case 'create':
                $response = $this->broadcastListCreate();
                break;
            
            case 'delete':
                $response = $this->broadcastListDelete();
                break;
            
            case 'delete_filter':
                $response = $this->broadcastListFilterDelete();
                break;
            
            case 'build':
                $response = $this->broadcastListBuild();
                break;
            
            case 'predefined':
                $response = $this->broadcastListBuildPredefined();
                break;
            
            case 'size': 
                $response = $this->broadcastListSize();
                break;
        }
        
        return $this->_response($response);
    }
    
    private function getBroadcastList() {
        $rules = array('required' => 'organisation_id, broadcast_list_id');

        $data = $this->request->data;

        $validated = $this->_validateParams($rules, $data);

        if ($validated != "NO_ERROR") {
            return $validated;
        }

        extract($data);
        
        $account = $this->ModuleSmsAccount->getAccount($organisation_id);
        
        if( $account ) {
            $list = $this->ModuleSmsBroadcastList->getList($account['ModuleSmsAccount']['id'], $broadcast_list_id);
            return array('status' => 'success', 'broadcast_list' => $list);
        }
        
        return array('status' => 'failed', 'message' => 'Invalid SMS Account Or Broadcast List Not Present');
    }

    private function broadcastLists($predefined_only = false) {

        $predefined = 0;
        
        $rules = array(
            'required' => 'organisation_id',
            'numeric' => 'predefined'
        );

        $data = $this->request->data;

        $validated = $this->_validateParams($rules, $data);

        if ($validated != "NO_ERROR") {
            return $validated;
        }

        extract($data);
        
        if( $predefined_only ) {
            return $this->ModuleSmsAccount->getPredefinedLists($organisation_id);
        }

        return $this->ModuleSmsAccount->getBroadcastLists($organisation_id, $predefined);
    }
    
    private function broadcastListCreate() {
        $data = $this->request->data;
        
        if( !isset($data['ModuleSmsBroadcastList']) ) {
            return array('status' => 'failed', 'message' => 'Invalid data format supplied');
        }
        
        $saved = $this->ModuleSmsBroadcastList->saveAll($data);
        
        // we'll cache the list size so we don't have to calculate it each time we need to view
        // anything
        if( $saved ) {
            $account_id = $data['ModuleSmsBroadcastList']['module_sms_account_id'];
            $broadcast_list_id = $this->ModuleSmsBroadcastList->id;

            $list_size = $this->ModuleSmsBroadcastList->getListSize($account_id, $broadcast_list_id);

            $this->ModuleSmsBroadcastList->save(array(
                'size' => $list_size['size']
            ));
        }
        
        return array('status' => 'success', 'message' => 'Data saved successfully');
    }
    
    private function broadcastListDelete() {
        
        $rules = array(
            'required' => 'organisation_id, broadcast_list_id'
        );

        $data = $this->request->data;

        $validated = $this->_validateParams($rules, $data);

        if ($validated != "NO_ERROR") {
            return $validated;
        }

        extract($data);
        
        $account = $this->ModuleSmsAccount->getAccount($organisation_id);
        
        if( $account ) {
            $this->ModuleSmsBroadcastList->updateAll(
                array('ModuleSmsBroadcastList.active' => 0), 
                array(
                    'ModuleSmsBroadcastList.id' => $broadcast_list_id, 
                    'ModuleSmsBroadcastList.module_sms_account_id' => $account['ModuleSmsAccount']['id']
                )
            );
            
            return array('status' => 'success', 'message' => 'Broadcast List Removed.');
        }
        
        return array('status' => 'failed', 'message' => 'No SMS Account Found. Delete operation failed.');
    }
    
    private function broadcastListBuild() {
        $limit = null;
        $offset = null;
        
        $rules = array(
            'required' => 'organisation_id, broadcast_list_id',
            'numeric' => 'limit, offset'
        );

        $data = $this->request->data;

        $validated = $this->_validateParams($rules, $data);

        if ($validated != "NO_ERROR") {
            return $validated;
        }

        extract($data);
        
        $account = $this->ModuleSmsAccount->getAccount($organisation_id);
        
        if( $account ) {
            return $this->ModuleSmsBroadcastList->buildList($account['ModuleSmsAccount']['id'], $broadcast_list_id, $limit, $offset);
        }
    }
    
    private function broadcastListBuildPredefined() {
        $limit = null;
        $offset = null;
        
        $rules = array(
            'required' => 'organisation_id, category_id',
            'numeric' => 'limit, offset'
        );

        $data = $this->request->data;

        $validated = $this->_validateParams($rules, $data);

        if ($validated != "NO_ERROR") {
            return $validated;
        }

        extract($data);
        
        $account = $this->ModuleSmsAccount->getAccount($organisation_id);
        
        if( $account ) {
            return $this->ModuleSmsBroadcastList->buildPredefinedList($account['ModuleSmsAccount']['id'], $category_id, $limit, $offset);
        }
    }
    
    private function broadcastListSize() {
        $rules = array(
            'required' => 'organisation_id, broadcast_list_id'
        );

        $data = $this->request->data;

        $validated = $this->_validateParams($rules, $data);

        if ($validated != "NO_ERROR") {
            return $validated;
        }

        extract($data);
        
        $account = $this->ModuleSmsAccount->getAccount($organisation_id);
        
        if( $account ) {
            return $this->ModuleSmsBroadcastList->getListSize($account['ModuleSmsAccount']['id'], $broadcast_list_id);
        }
    }
    
    private function broadcastListFilterDelete() {
        
        $rules = array(
            'required' => 'organisation_id, filter_id'
        );

        $data = $this->request->data;

        $validated = $this->_validateParams($rules, $data);

        if ($validated != "NO_ERROR") {
            return $validated;
        }

        extract($data);
        
        $account = $this->ModuleSmsAccount->getAccount($organisation_id);
        
        if( $account ) {
            $this->ModuleSmsBroadcastList->ModuleSmsBroadcastListFilter->updateAll(
                array('ModuleSmsBroadcastListFilter.active' => 0), 
                array(
                    'ModuleSmsBroadcastListFilter.id' => $filter_id,
                )
            );
            
            return array('status' => 'success', 'message' => 'Broadcast List Filter Removed.');
        }
        
        return array('status' => 'failed', 'message' => 'No SMS Account Found. Delete operation failed.');
    }

    public function contacts($action = 'list') {

        $response = array();

        switch ($action) {
            case 'list':
                $response = $this->contactsList();
                break;

            case 'add':
                $response = $this->contactsAdd();
                break;
            
            case 'search':
                $response = $this->contactsSearch();
                break;
            
            case 'create_list':
                $response = $this->contactsCreateList();
                break;
            
            case 'numbers':
                $response = $this->contactsByNumbers();
                break;
        }

        return $this->_response($response);
    }

    private function contactsList() {
        $offset = 0;
        $limit = 10;
        
        $rules = array(
            'required' => 'organisation_id', 'broadcast_list_id',
            'numeric' => 'offset, limit'
        );

        $data = $this->request->data;

        $validated = $this->_validateParams($rules, $data);

        if ($validated != "NO_ERROR") {
            return $validated;
        }

        extract($data);

        return $this->ModuleSmsAccount->getContactsList($organisation_id, $broadcast_list_id, $limit, $offset);
    }

    private function contactsAdd() {

        $rules = array('organisation_id', 'broadcast_list_id', 'member_id');

        $data = $this->request->data;

        $validated = $this->_validateParams($rules, $data);

        if ($validated != "NO_ERROR") {
            return $validated;
        }

        extract($data);

        return $this->ModuleSmsBroadcastListContact->addContact($organisation_id, $broadcast_list_id, $member_id);
    }

    public function account() {
        
        $rules = array('required' => 'organisation_id');

        $data = $this->request->data;

        $validated = $this->_validateParams($rules, $data);

        if ($validated != "NO_ERROR") {
            return $validated;
        }

        extract($data);
        
        $account = $this->ModuleSmsAccount->getAccount($organisation_id);
        
        if( $account ) {
            return $this->_response(array(
                'status' => 'success',
                'account' => array(
                    'organisation_id' => $account['ModuleSmsAccount']['organisation_id'],
                    'account_id' => $account['ModuleSmsAccount']['id'],
                    'balance' => $account['ModuleSmsAccount']['account_balance'],
                    'sender_id' => $account['ModuleSmsAccount']['sender_id'],
                    'active' => $account['ModuleSmsAccount']['active']
                )
            ));
        }
        
        return $this->_response(array(
            'status' => 'failed',
            'message' => 'No account found for organisation'
        ));
    }
    
    public function instant($action) {
        $response = array();
        
        switch($action) {
            case 'history':
                $response = $this->instantHistory();
                break;
        }
        
        return $this->_response($response);
    }
    
    private function instantHistory() {
        $limit = 15;
        $offset = 0;
        
        $rules = array(
            'required' => 'organisation_id',
            'numeric' => 'limit, offset'
        );

        $data = $this->request->data;

        $validated = $this->_validateParams($rules, $data);

        if ($validated != "NO_ERROR") {
            return $validated;
        }

        extract($data);
        
        return $this->ModuleSmsAccountInstantMessage->getHistory($organisation_id, $limit, $offset);
    }

    public function send($action) {
        $response = array();

        switch ($action) {
            case 'instant':
                $response = $this->sendInstantMessage();
                break;

            case 'broadcast':
                $response = $this->scheduleBroadcastMessage();
                break;
        }

        return $this->_response($response);
    }

    private function sendInstantMessage() {
        $rules = array('required' => 'organisation_id', 'contacts', 'message');

        $data = $this->request->data;

        $validated = $this->_validateParams($rules, $data);

        if ($validated != "NO_ERROR") {
            return $validated;
        }

        extract($data);
        
        $sms_account = $this->ModuleSmsAccount->getAccount($organisation_id);
        
        if( !$sms_account ) {
            return array('status' => 'failed', 'error_type' => 'no_account', 'message' => 'An SMS Messaging Account is not active for the specified organisation');
        }

        if (!$this->ModuleSmsAccount->hasCredit($organisation_id)) {
            ClassRegistry::init('OrganisationNotification')->add($organisation_id, 'sms_low_credit');
            return array('status' => 'failed', 'error_type' => 'no_credit', 'message' => 'Account does not have enough credit. Please topup to continue.');
        }

        $time = new DateTime();
        $errors = array();

        foreach ($contacts as $contact) {
            $time->add(new DateInterval("PT10S"));

            $response = $this->Sms->send($contact['number'], $message, $sms_account['ModuleSmsAccount']['sender_id']);
            $sent = 1;

            if (isset($response['error'])) {
                $errors[] = $response['error'];
                $sent = 0;
            }

            $this->ModuleSmsAccountInstantMessage->logMessage($organisation_id, $contact['member_id'], $contact['number'], $message, $time->format('Y-m-d H:i:s'), $sent);

            if ($sent) {
                $this->ModuleSmsAccount->deductCredit($organisation_id);
            }
        }

        if (count($errors) > 0) {
            return array('status' => 'warning', 'message' => 'Messages sent with errors', 'errors' => $errors);
        }

        return array(
            'status' => 'success',
            'message' => 'Instant message(s) successfully sent. ',
            'account_balance' => $this->ModuleSmsAccount->getAccountBalance($organisation_id)
        );
    }

    private function scheduleBroadcastMessage() {
        $rules = array('required' => 'organisation_id', 'schedule', 'message');

        $data = $this->request->data;

        $validated = $this->_validateParams($rules, $data);

        if ($validated != "NO_ERROR") {
            return $validated;
        }

        extract($data);
        
        $sms_account = $this->ModuleSmsAccount->getAccount($organisation_id);
        
        if( !$sms_account ) {
            return array('status' => 'failed', 'error_type' => 'no_account', 'message' => 'An SMS Messaging Account is not active for the specified organisation');
        }
        
        $organisation_slug = $sms_account['Organisation']['slug'];

        // check if organisation has any credit at all
        if (!$this->ModuleSmsAccount->hasCredit($organisation_id)) {
            $message = 'Account does not have enough credit. Please topup to continue.';
            $url = Router::url("/$organisation_slug/sms/topup");
                
            $this->OrganisationNotification->add($organisation_id, $message, 'Low Credit', $url);
            
            return array('status' => 'failed', 'error_type' => 'no_credit', 'message' => $message);
        }
        
        // schedule the broadcast if all rules are met
        if( isset($data['broadcast_list_id'])  ) {
            // check if organisation credit is enough to send messages to the entire list
            $broadcast_list = $this->ModuleSmsBroadcastList->getList($sms_account['ModuleSmsAccount']['id'], $broadcast_list_id);

            if( $sms_account['ModuleSmsAccount']['account_balance'] < $broadcast_list['size'] ) {
                $message = "Your SMS Account does not have enough credit. Please topup to be able to broadcast messages to <b>{$broadcast_list['name']}</b>";
                $url = Router::url("/$organisation_slug/sms/topup");

                $this->OrganisationNotification->add($organisation_id, 'sms_low_credit');

                return array('status' => 'failed', 'error_type' => 'not_enough_credit', 'message' => $message);
            }
            
            $response = $this->ModuleSmsAccount->scheduleBroadcast($sms_account['ModuleSmsAccount']['id'], $broadcast_list_id, $schedule, $message);
        }
        
        else if( isset($data['category_id']) ) {
            $size = ClassRegistry::init('OrganisationMember')->getTotalMembersByCategory($data['organisation_id'], $data['category_id']);
            
            if( $sms_account['ModuleSmsAccount']['account_balance'] < $size ) {
                $message = "Your SMS Account does not have enough credit. Please topup to be able to broadcast messages.";
                $url = Router::url("/$organisation_slug/sms/topup");

                $this->OrganisationNotification->add($organisation_id, 'sms_low_credit');

                return array('status' => 'failed', 'error_type' => 'not_enough_credit', 'message' => $message);
            }
            
            $response = $this->ModuleSmsAccount->schedulePredefinedBroadcast($sms_account['ModuleSmsAccount']['id'], $category_id, $schedule, $message);
        }
        
        else {
            $response = array('status' => 'failed', 'message' => 'Invalid request parameters. Missing broadcast_list_id or category_id');
        }
        
        $response['data'] = $data;
        
        return $response;
    }
    
    private function broadcastHistory() {
        $limit = 15;
        $offset = 0;
        
        $rules = array(
            'required' => 'organisation_id',
            'numeric' => 'limit, offset'
        );

        $data = $this->request->data;

        $validated = $this->_validateParams($rules, $data);

        if ($validated != "NO_ERROR") {
            return $validated;
        }

        extract($data);
        
        return $this->ModuleSmsAccountBroadcast->getHistory($organisation_id, $limit, $offset);
    }

    public function contactsSearch() {
        $limit = 10;
        
        $rules = array(
            'required' => 'organisation_id', 'term',
            'numeric' => 'limit'
        );

        $data = $this->request->data;

        $validated = $this->_validateParams($rules, $data);

        if ($validated != "NO_ERROR") {
            return $validated;
        }

        extract($data);
        
        $sql = sprintf("SELECT m.id, mpn.type, mpn.number, m.first_name, m.last_name FROM members m "
                . "INNER JOIN member_phone_numbers mpn ON mpn.member_id = m.id "
                . "INNER JOIN organisation_members om ON om.member_id = m.id "
                . "WHERE om.organisation_id = %d AND "
                . "((CONCAT(m.first_name, ' ', m.last_name) LIKE '%%%s%%') OR (mpn.number LIKE '%%%s%%')) "
                . "ORDER BY m.first_name, m.last_name "
                . "LIMIT %d",
                $organisation_id, $term, $term, $limit);
        
        $result = $this->ModuleSmsAccount->query($sql);
        
        $response = array();
        
        foreach($result as $row) {
            $response[] = array(
                'id' => $row['m']['id'],
                'label' => $row['m']['first_name'] . " " . $row['m']['last_name'],
                'number' => $row['mpn']['number'],
                'type' => ucfirst($row['mpn']['type']),
                'member_id' => $row['m']['id']
            );
        }
        
        return $response;
    }
    
    public function contactsByNumbers() {
        $rules = array(
            'required' => 'organisation_id', 'numbers'
        );

        $data = $this->request->data;

        $validated = $this->_validateParams($rules, $data);

        if ($validated != "NO_ERROR") {
            return $validated;
        }

        extract($data);
        
        $sms_account = $this->ModuleSmsAccount->getAccount($organisation_id);
        
        if( $sms_account ) {
            $query = sprintf("SELECT Member.id, Member.first_name, Member.last_name, Member.title, Member.middle_name, MemberPhoneNumber.number, MemberPhoneNumber.type "
                    . "FROM members Member "
                    . "INNER JOIN member_phone_numbers MemberPhoneNumber ON MemberPhoneNumber.member_id = Member.id AND MemberPhoneNumber.number IN ('%s') "
                    . "INNER JOIN organisation_members OrganisationMember ON OrganisationMember.member_id = Member.id AND OrganisationMember.organisation_id = %d ",
                    implode("','", $numbers), $organisation_id);
            
            $result = ClassRegistry::init('OrganisationMember')->query($query);
            
            $contacts = array();
            
            foreach($result as $res) {
                $contacts[] = array(
                    'id' => $res['Member']['id'],
                    'member_id' => $res['Member']['id'],
                    'number' => $res['MemberPhoneNumber']['number'],
                    'value' => $res['Member']['first_name'] . ' ' . $res['Member']['last_name'],
                    'type' => $res['MemberPhoneNumber']['type']
                );
            }
            
            return array('status' => 'success', 'contacts' => $contacts);
        }
        
        return array('status' => 'failed', 'message' => 'SMS Account Not Available');
    }
}
